diff --git a/kcal/htmlexport.cpp b/kcal/htmlexport.cpp index 9d09d20df..db7f1fe79 100644 --- a/kcal/htmlexport.cpp +++ b/kcal/htmlexport.cpp @@ -1,782 +1,781 @@ /* This file is part of the kcal library. Copyright (c) 2000,2001 Cornelius Schumacher Copyright (C) 2004 Reinhold Kainhofer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "htmlexport.h" #include "htmlexportsettings.h" #include "incidenceformatter.h" #include "calendar.h" #include "event.h" #include "todo.h" #ifndef KORG_NOKABC #include "kabc/stdaddressbook.h" #endif #include #include #include #include #include #include #include #include #include #include using namespace KCal; static QString cleanChars( const QString &txt ); //@cond PRIVATE class KCal::HtmlExport::Private { public: Private( Calendar *calendar, HTMLExportSettings *settings ) : mCalendar( calendar ), mSettings( settings ) {} Calendar *mCalendar; HTMLExportSettings *mSettings; QMap mHolidayMap; }; //@endcond HtmlExport::HtmlExport( Calendar *calendar, HTMLExportSettings *settings ) : d( new Private( calendar, settings ) ) { } HtmlExport::~HtmlExport() { delete d; } bool HtmlExport::save( const QString &fileName ) { QString fn( fileName ); if ( fn.isEmpty() && d->mSettings ) { fn = d->mSettings->outputFile(); } if ( !d->mSettings || fn.isEmpty() ) { return false; } QFile f( fileName ); if ( !f.open( QIODevice::WriteOnly ) ) { return false; } QTextStream ts( &f ); bool success = save( &ts ); f.close(); return success; } bool HtmlExport::save( QTextStream *ts ) { if ( !d->mSettings ) { return false; } ts->setCodec( "UTF-8" ); - // Write HTML header *ts << "\n"; + *ts << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"<" << endl; *ts << " \n"; + *ts << "UTF-8\" />"<mSettings->pageTitle().isEmpty() ) { - *ts << " " << d->mSettings->pageTitle() << "\n"; + *ts << " " << d->mSettings->pageTitle() << ""<\n"; + *ts << " \n"; - *ts << "\n"; + *ts << " "<"<mSettings->eventView() || d->mSettings->monthView() || d->mSettings->weekView() ) { if ( !d->mSettings->eventTitle().isEmpty() ) { - *ts << "

" << d->mSettings->eventTitle() << "

\n"; + *ts << "

" << d->mSettings->eventTitle() << "

"<mSettings->weekView() ) { createWeekView( ts ); } // Write Month View if ( d->mSettings->monthView() ) { createMonthView( ts ); } // Write Event List if ( d->mSettings->eventView() ) { createEventList( ts ); } } // Write Todo List if ( d->mSettings->todoView() ) { if ( !d->mSettings->todoListTitle().isEmpty() ) { - *ts << "

" << d->mSettings->todoListTitle() << "

\n"; + *ts << "

" << d->mSettings->todoListTitle() << "

"<mSettings->journalView() ) { if ( !d->mSettings->journalTitle().isEmpty() ) { - *ts << "

" << d->mSettings->journalTitle() << "

\n"; + *ts << "

" << d->mSettings->journalTitle() << "

"<mSettings->freeBusyView() ) { if ( !d->mSettings->freeBusyTitle().isEmpty() ) { - *ts << "

" << d->mSettings->freeBusyTitle() << "

\n"; + *ts << "

" << d->mSettings->freeBusyTitle() << "

"<\n"; + *ts << ""<" << i18nc( "@title month and year", "%1 %2", hMon, hYear ) - << "\n"; + << ""<weekStartDay() == 1 ) { start = start.addDays( 1 - start.dayOfWeek() ); } else { if ( start.dayOfWeek() != 7 ) { start = start.addDays( -start.dayOfWeek() ); } } - *ts << "\n"; + *ts << "
"<"; for ( int i=0; i < 7; ++i ) { *ts << ""; } - *ts << "\n"; + *ts << ""<\n"; + *ts << " "<
" << KGlobal::locale()->calendar()->weekDayName( start.addDays(i) ) << "
"; *ts << "
mHolidayMap.contains( start ) || start.dayOfWeek() == 7 ) { *ts << "class=\"dateholiday\""; } else { *ts << "class=\"date\""; } *ts << ">" << QString::number( start.day() ); if ( d->mHolidayMap.contains( start ) ) { *ts << " " << d->mHolidayMap[start] << ""; } *ts << "
"; Event::List events = d->mCalendar->events( start, d->mCalendar->timeSpec(), EventSortStartDate, SortDirectionAscending ); if ( events.count() ) { *ts << ""; Event::List::ConstIterator it; for ( it = events.constBegin(); it != events.constEnd(); ++it ) { if ( checkSecrecy( *it ) ) { createEvent( ts, *it, start, false ); } } *ts << "
"; } else { *ts << " "; } - *ts << "
\n"; + *ts << ""<\n"; + *ts << " "<\n"; + *ts << ""< 12 ) { startyear += 1; startmonth = 1; } start.setYMD( startyear, startmonth, 1 ); end.setYMD( start.year(), start.month(), start.daysInMonth() ); } } void HtmlExport::createEventList( QTextStream *ts ) { int columns = 3; - *ts << "\n"; - *ts << " \n"; + *ts << "
"<"<" << i18nc( "@title:column event start time", - "Start Time" ) << "\n"; + "Start Time" ) << ""<" << i18nc( "@title:column event end time", - "End Time" ) << "\n"; + "End Time" ) << ""<" << i18nc( "@title:column event description", - "Event" ) << "\n"; + "Event" ) << ""<mSettings->eventLocation() ) { *ts << " \n"; + "Location" ) << ""<mSettings->eventCategories() ) { *ts << " \n"; + "Categories" ) << ""<mSettings->eventAttendees() ) { *ts << " \n"; + "Attendees" ) << ""<\n"; + *ts << " "<mCalendar->events( dt, d->mCalendar->timeSpec(), EventSortStartDate, SortDirectionAscending ); if ( events.count() ) { *ts << " \n"; + << ""<\n"; + *ts << "
" << i18nc( "@title:column event locatin", - "Location" ) << "" << i18nc( "@title:column event categories", - "Categories" ) << "" << i18nc( "@title:column event attendees", - "Attendees" ) << "
" << KGlobal::locale()->formatDate( dt ) - << "
"<summary(); - *ts << " \n"; + *ts << " "<allDay() ) { if ( event->isMultiDay( d->mCalendar->timeSpec() ) && ( event->dtStart().date() != date ) ) { - *ts << "  \n"; + *ts << "  "<" << IncidenceFormatter::timeToString( event->dtStart(), true, d->mCalendar->timeSpec() ) - << "\n"; + << ""<isMultiDay( d->mCalendar->timeSpec() ) && ( event->dtEnd().date() != date ) ) { - *ts << "  \n"; + *ts << "  "<" << IncidenceFormatter::timeToString( event->dtEnd(), true, d->mCalendar->timeSpec() ) - << "\n"; + << ""<  \n"; + *ts << "   "<\n"; - *ts << " " << cleanChars( event->summary() ) << "\n"; + *ts << " "<" << cleanChars( event->summary() ) << ""<description().isEmpty() ) { - *ts << "

" << breakString( cleanChars( event->description() ) ) << "

\n"; + *ts << "

" << breakString( cleanChars( event->description() ) ) << "

"<\n"; + *ts << " "<mSettings->eventLocation() ) { - *ts << " \n"; + *ts << " "<\n"; + *ts << " "<mSettings->eventCategories() ) { - *ts << " \n"; + *ts << " "<\n"; + *ts << " "<mSettings->eventAttendees() ) { - *ts << " \n"; + *ts << " "<\n"; + *ts << " "<\n"; + *ts << " "<mCalendar->todos(); int index = 0; while ( index < rawTodoList.count() ) { Todo *ev = rawTodoList[ index ]; Todo *subev = ev; if ( ev->relatedTo() ) { if ( ev->relatedTo()->type() == "Todo" ) { if ( !rawTodoList.contains( static_cast( ev->relatedTo() ) ) ) { rawTodoList.append( static_cast( ev->relatedTo() ) ); } } } index = rawTodoList.indexOf( subev ); ++index; } // FIXME: Sort list by priorities. This is brute force and should be // replaced by a real sorting algorithm. Todo::List todoList; Todo::List::ConstIterator it; for ( int i = 1; i <= 9; ++i ) { for ( it = rawTodoList.constBegin(); it != rawTodoList.constEnd(); ++it ) { if ( (*it)->priority() == i && checkSecrecy( *it ) ) { todoList.append( *it ); } } } for ( it = rawTodoList.constBegin(); it != rawTodoList.constEnd(); ++it ) { if ( (*it)->priority() == 0 && checkSecrecy( *it ) ) { todoList.append( *it ); } } int columns = 3; - *ts << "\n"; - *ts << " \n"; - *ts << " \n"; - *ts << " \n"; - *ts << " \n"; + *ts << "
" << i18nc( "@title:column", "To-do" ) << "" << i18nc( "@title:column to-do priority", "Priority" ) << "" << i18nc( "@title:column to-do percent completed", "Completed" ) << "
"<"<" << i18nc( "@title:column", "To-do" ) << ""<" << i18nc( "@title:column to-do priority", "Priority" ) << ""<" << i18nc( "@title:column to-do percent completed", "Completed" ) << ""<mSettings->taskDueDate() ) { - *ts << " \n"; + *ts << " "<mSettings->taskLocation() ) { - *ts << " \n"; + *ts << " "<mSettings->taskCategories() ) { - *ts << " \n"; + *ts << " "<mSettings->taskAttendees() ) { - *ts << " \n"; + *ts << " "<\n"; + *ts << " "<relatedTo() ) { createTodo( ts, *it ); } } // Create sub-level lists for ( it = todoList.constBegin(); it != todoList.constEnd(); ++it ) { Incidence::List relations = (*it)->relations(); if ( relations.count() ) { // Generate sub-to-do list - *ts << " \n"; + *ts << " "<uid() << "\">" << i18nc( "@title:column sub-to-dos of the parent to-do", "Sub-To-dos of: " ) << "uid() << "\">" << cleanChars( (*it)->summary() ) - << "\n"; - *ts << " \n"; + << ""<"<( *it2 ); if ( ev3 && ev3->priority() == i ) { sortedList.append( ev3 ); } } } Incidence::List::ConstIterator it2; for ( it2 = relations.constBegin(); it2 != relations.constEnd(); ++it2 ) { Todo *ev3 = dynamic_cast( *it2 ); if ( ev3 && ev3->priority() == 0 ) { sortedList.append( ev3 ); } } Todo::List::ConstIterator it3; for ( it3 = sortedList.constBegin(); it3 != sortedList.constEnd(); ++it3 ) { createTodo( ts, *it3 ); } } } - *ts << "
" << i18nc( "@title:column to-do due date", "Due Date" ) << "" << i18nc( "@title:column to-do due date", "Due Date" ) << "" << i18nc( "@title:column to-do location", "Location" ) << "" << i18nc( "@title:column to-do location", "Location" ) << "" << i18nc( "@title:column to-do categories", "Categories" ) << "" << i18nc( "@title:column to-do categories", "Categories" ) << "" << i18nc( "@title:column to-do attendees", "Attendees" ) << "" << i18nc( "@title:column to-do attendees", "Attendees" ) << "
\n"; + *ts << ""<isCompleted(); Incidence::List relations = todo->relations(); - *ts << "\n"; + *ts << ""<\n"; - *ts << " uid() << "\">\n"; - *ts << " " << cleanChars( todo->summary() ) << "\n"; + *ts << "\">"<uid() << "\">"<" << cleanChars( todo->summary() ) << ""<description().isEmpty() ) { - *ts << "

" << breakString( cleanChars( todo->description() ) ) << "

\n"; + *ts << "

" << breakString( cleanChars( todo->description() ) ) << "

"<uid() << "\">" << i18nc( "@title:column sub-to-dos of the parent to-do", - "Sub-To-dos" ) << "\n"; + "Sub-To-dos" ) << ""<\n"; + *ts << " "<\n"; - *ts << " " << todo->priority() << "\n"; - *ts << " \n"; + *ts << ">"<priority() <"<\n"; + *ts << ">"<percentComplete() ) << "\n"; - *ts << " \n"; + "%1 %", todo->percentComplete() ) <"<mSettings->taskDueDate() ) { *ts << " \n"; + *ts << ">"<hasDueDate() ) { - *ts << " " << IncidenceFormatter::dateToString(todo->dtDue(true)) << "\n"; + *ts << " " << IncidenceFormatter::dateToString(todo->dtDue(true)) <\n"; + *ts << " "<mSettings->taskLocation() ) { *ts << " \n"; + *ts << ">"<\n"; + *ts << " "<mSettings->taskCategories() ) { *ts << " \n"; + *ts << ">"<\n"; + *ts << " "<mSettings->taskAttendees() ) { *ts << " \n"; + *ts << ">"<\n"; + *ts << " "<\n"; + *ts << ""<mCalendar->journals(); // FIXME: Implement this! } void HtmlExport::createFreeBusyView( QTextStream *ts ) { Q_UNUSED( ts ); // FIXME: Implement this! } bool HtmlExport::checkSecrecy( Incidence *incidence ) { int secrecy = incidence->secrecy(); if ( secrecy == Incidence::SecrecyPublic ) { return true; } if ( secrecy == Incidence::SecrecyPrivate && !d->mSettings->excludePrivate() ) { return true; } if ( secrecy == Incidence::SecrecyConfidential && !d->mSettings->excludeConfidential() ) { return true; } return false; } void HtmlExport::formatLocation( QTextStream *ts, Incidence *incidence ) { if ( !incidence->location().isEmpty() ) { - *ts << " " << cleanChars( incidence->location() ) << "\n"; + *ts << " " << cleanChars( incidence->location() ) <categoriesStr().isEmpty() ) { - *ts << " " << cleanChars( incidence->categoriesStr() ) << "\n"; + *ts << " " << cleanChars( incidence->categoriesStr() ) <attendees(); if ( attendees.count() ) { *ts << ""; #ifndef KORG_NOKABC KABC::AddressBook *add_book = KABC::StdAddressBook::self( true ); KABC::Addressee::List addressList; addressList = add_book->findByEmail( incidence->organizer().email() ); if ( !addressList.isEmpty() ) { KABC::Addressee o = addressList.first(); if ( !o.isEmpty() && addressList.size() < 2 ) { *ts << "organizer().email() << "\">"; - *ts << cleanChars( o.formattedName() ) << "\n"; + *ts << cleanChars( o.formattedName() ) << ""<organizer().fullName(); } } #else *ts << incidence->organizer().fullName(); #endif *ts << "
"; Attendee::List::ConstIterator it; for ( it = attendees.constBegin(); it != attendees.constEnd(); ++it ) { Attendee *a = *it; if ( !a->email().isEmpty() ) { *ts << "email(); *ts << "\">" << cleanChars( a->name() ) << ""; } else { *ts << " " << cleanChars( a->name() ); } - *ts << "
" << "\n"; + *ts << "
" <"; } return out; } } void HtmlExport::createFooter( QTextStream *ts ) { // FIXME: Implement this in a translatable way! QString trailer = i18nc( "@info/plain", "This page was created " ); /* bool hasPerson = false; bool hasCredit = false; bool hasCreditURL = false; QString mail, name, credit, creditURL;*/ if ( !d->mSettings->eMail().isEmpty() ) { if ( !d->mSettings->name().isEmpty() ) { trailer += i18nc( "@info/plain page creator email link with name", "by %2", d->mSettings->eMail(), d->mSettings->name() ); } else { trailer += i18nc( "@info/plain page creator email link", "by %2", d->mSettings->eMail(), d->mSettings->eMail() ); } } else { if ( !d->mSettings->name().isEmpty() ) { trailer += i18nc( "@info/plain page creator name only", "by %1 ", d->mSettings->name() ); } } if ( !d->mSettings->creditName().isEmpty() ) { if ( !d->mSettings->creditURL().isEmpty() ) { trailer += i18nc( "@info/plain page credit with name and link", "with %2", d->mSettings->creditURL(), d->mSettings->creditName() ); } else { trailer += i18nc( "@info/plain page credit name only", "with %1", d->mSettings->creditName() ); } } - *ts << "

" << trailer << "

\n"; + *ts << "

" << trailer << "

"<', ">" ); txt = txt.replace( '\"', """ ); txt = txt.replace( QString::fromUtf8( "ä" ), "ä" ); txt = txt.replace( QString::fromUtf8( "Ä" ), "Ä" ); txt = txt.replace( QString::fromUtf8( "ö" ), "ö" ); txt = txt.replace( QString::fromUtf8( "Ö" ), "Ö" ); txt = txt.replace( QString::fromUtf8( "ü" ), "ü" ); txt = txt.replace( QString::fromUtf8( "Ü" ), "Ü" ); txt = txt.replace( QString::fromUtf8( "ß" ), "ß" ); txt = txt.replace( QString::fromUtf8( "€" ), "€" ); txt = txt.replace( QString::fromUtf8( "é" ), "é" ); return txt; } QString HtmlExport::styleSheet() const { if ( !d->mSettings->styleSheet().isEmpty() ) { return d->mSettings->styleSheet(); } QString css; if ( QApplication::isRightToLeft() ) { css += " body { background-color:white; color:black; direction: rtl }\n"; css += " td { text-align:center; background-color:#eee }\n"; css += " th { text-align:center; background-color:#228; color:white }\n"; css += " td.sumdone { background-color:#ccc }\n"; css += " td.done { background-color:#ccc }\n"; css += " td.subhead { text-align:center; background-color:#ccf }\n"; css += " td.datehead { text-align:center; background-color:#ccf }\n"; css += " td.space { background-color:white }\n"; css += " td.dateholiday { color:red }\n"; } else { css += " body { background-color:white; color:black }\n"; css += " td { text-align:center; background-color:#eee }\n"; css += " th { text-align:center; background-color:#228; color:white }\n"; css += " td.sum { text-align:left }\n"; css += " td.sumdone { text-align:left; background-color:#ccc }\n"; css += " td.done { background-color:#ccc }\n"; css += " td.subhead { text-align:center; background-color:#ccf }\n"; css += " td.datehead { text-align:center; background-color:#ccf }\n"; css += " td.space { background-color:white }\n"; css += " td.date { text-align:left }\n"; css += " td.dateholiday { text-align:left; color:red }\n"; } return css; } void HtmlExport::addHoliday( const QDate &date, const QString &name ) { if ( d->mHolidayMap[date].isEmpty() ) { d->mHolidayMap[date] = name; } else { d->mHolidayMap[date] = i18nc( "@info/plain holiday by date and name", "%1, %2", d->mHolidayMap[date], name ); } } QDate HtmlExport::fromDate() const { return d->mSettings->dateStart().date(); } QDate HtmlExport::toDate() const { return d->mSettings->dateEnd().date(); }